//
//    Copyright (C) 2012  OinkStudio
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
package com.marakana.obolo;

import game.CPU;
import game.Obolo;
import game.Player;
import graphics.OboloGraphicsView;
import graphics.PackageRulesManager;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import database.DBAdapter;

public class SelectDeckActivity extends Activity {
	private TableLayout tlSelectedObolos;
	private Button cmdNext;
	private int sizeDeck;
	private int owner;
	private Player player;
	private int widthRatio;
	private SharedPreferences prefs;
	private String selectedPlayer;
	private Bundle extras;
	
	private final int VISIBLE = 0;
	private final int INVISIBLE = 4;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.select_deck);

		extras = getIntent().getExtras();

		int[] dimension = extras.getIntArray("dimension");
		selectedPlayer = extras.getString("selectedplayer");

		
		// tria qui es el jugador que li toca seleccionar
		player = (Player) extras.getSerializable(selectedPlayer);
		if (selectedPlayer.equals("rival") && player.isHuman()){
			owner = 0;
		}
		else{
			owner = 1;
		}
		/*
		 * if(selectDeckPlayer == 1) player = (Player)
		 * extras.getSerializable("user"); else player = (Player)
		 * extras.getSerializable("rival");
		 */

		// Calcula la mida dels decks dels jugadors
		sizeDeck = getPlayerDeckLength(dimension[0], dimension[1]);

		// Si el rival no es un jugador huma llavors tria la maquina
		if (!player.isHuman())
			iaSelectDeck();
	

		// Layout pare
		LinearLayout lySelectDeck = (LinearLayout) findViewById(R.id.lySelectDeck);

		// Afegeix el textView d'informacio per a la seleccio de els obolos
		TextView txtDeck = new TextView(this);
		txtDeck.setText("Obolos seleccionats");
		txtDeck.setPadding(0, 2, 0, 2);

		lySelectDeck.addView(txtDeck);

		// matriu d'una fila amb tantes posicions com obolos es necessiten, al
		// principi esta buida
		tlSelectedObolos = new TableLayout(this);
		TableRow trSelectedObolos = new TableRow(this);

		// Redimensiona el deck de seleccio segona la pantalla
		boundsViewsOnScreen(sizeDeck);

		// Afegeix els obolosGraphics al deck de selecci�
		for (int count = 0; count < sizeDeck; count++) {
			OboloGraphicsView ogvObolo = new OboloGraphicsView(this, null);
			// Li dona la mida al obolo segons l'amplada de la pantalla
			ogvObolo.setBoundsWidth(widthRatio);
			trSelectedObolos.addView(ogvObolo);
		}

		// Introdueix la fila dins del table layout
		tlSelectedObolos.addView(trSelectedObolos);

		// Introduexi el View del deck de seleccio en el layout pare
		lySelectDeck.addView(tlSelectedObolos);

		// Crea el boto de continuar
		cmdNext = new Button(this);
		cmdNext.setText("Continuar");
		cmdNext.setEnabled(false);
		cmdNext.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// Afegeix el deck seleccionat al jugador
				player.setDeck(getDeck());

				throwIntentToNewGame();
			}
		});

		// Afegeix el bot� de continuar en el layout pare
		lySelectDeck.addView(cmdNext);

		// Afegeix el textView d'informacio per seleccionar els obolos de la BD
		TextView txtSelect = new TextView(this);
		txtSelect.setText("Selecciona els obolos amb els que vols jugar");
		lySelectDeck.addView(txtSelect);

		// Crea el scroll View de la llibreria de seleccio de els obolos
		// i l'adapter de la base de dades per fer els selects
		ScrollView svLibrary = new ScrollView(this);
		DBAdapter dbAdapter = new DBAdapter(this);
		// Obre la BD
		dbAdapter.open();

		// s'afegeix una matriu al layout de selectDeck, on es posaran tots els
		// obolos que posseix el jugador
		TableLayout tlLibrary = new TableLayout(this);
		tlLibrary.setGravity(Gravity.CENTER);
		Cursor cPlayerObolo = dbAdapter.getAllPlayerObolo();
		String north, east, south, west;
		int column = 0;
		int rows = 0;
		int numObolosPerColumn = 5;

		// Redimensiona la llibrerio de obolos del jugador segona la pantalla
		// el 0.25 es per separar la llibreria del scrollView
		boundsViewsOnScreen(numObolosPerColumn + 0.25);

		// Captura els obolos de la base de dades i els va afegint a la
		// llibreria per poderlos seleccionar
		int quantityAux = 0;
		boolean nextObolo;
		TableRow trLibrary = null;
		if (cPlayerObolo.moveToFirst()) {
			do {
				
				nextObolo = false;		
				do {	
					if(trLibrary == null){
						trLibrary = new TableRow(this);
						trLibrary.setPadding(2, 1, 2, 1);
						tlLibrary.addView(trLibrary);
					}
					// Recupera el obolo del registre actual de la taula
					// PlayerObolo
					Cursor cObolo = dbAdapter.getObolo(cPlayerObolo
							.getLong(cPlayerObolo.getColumnIndex("idObolo")));
					// Recuperem els diferents valors de cada punt cardinal
					north = String.valueOf(cObolo.getString(cObolo
							.getColumnIndex("north")));
					south = String.valueOf(cObolo.getString(cObolo
							.getColumnIndex("south")));
					east = String.valueOf(cObolo.getString(cObolo
							.getColumnIndex("east")));
					west = String.valueOf(cObolo.getString(cObolo
							.getColumnIndex("west")));

					long quantity = cPlayerObolo.getLong(cPlayerObolo
							.getColumnIndex("quantity"));

					do {
						// Crea el obolo com a objecte i graficament
						Obolo obolo = new Obolo(new String[] { north, south,
								east, west });
						obolo.setOwner(owner);
						OboloGraphicsView ogvObolo = new OboloGraphicsView(
								this, obolo);
						// Li dona la mida al obolo segons l'amplada de la
						// pantalla
						ogvObolo.setBoundsWidth(widthRatio);
						setTouchOgvObolo(ogvObolo);
						trLibrary.addView(ogvObolo);
						column++;
						quantityAux++;
					} while (column < numObolosPerColumn
							&& quantityAux < quantity);
					// Si s'han posat tants obolos com en te d'aquell tipus,
					// sortim del bucle i passem al
					// seguent obolo de la taula PlayerObolo
					if (quantityAux == quantity) {
						quantityAux = 0;	
						nextObolo = true;
					}					
					if (column == numObolosPerColumn) {
						column = 0;
						//tlLibrary.addView(trLibrary);
						trLibrary = null;
						rows++;
					}	
				} while (!nextObolo);
							
			} while (cPlayerObolo.moveToNext());
		}
		svLibrary.addView(tlLibrary);
		// Tanca la BD
		dbAdapter.close();
		// Afegeix la llibreria acabada en el layout pare
		lySelectDeck.addView(svLibrary);
	}

	private void throwIntentToNewGame() {
		// Empaqueta i envia el Intent al proxim SelectDeckActivity o a NewGame
		// depenent de si els jugadors son maquinas o usuaris
		Intent newGame;
		if (selectedPlayer.equals("user")) {
			// Crea el intent per a seleccionar el deck de 2n jugador
			newGame = new Intent(this, SelectDeckActivity.class);
			// Afegeix les variables per pasarles a la proxima activity
			newGame.putExtras(extras);
			newGame.putExtra(selectedPlayer, player);
			// Asigna el proxim jugador que seleccionara deck
			selectedPlayer = "rival";
			newGame.putExtra("selectedplayer", selectedPlayer);
		} else {
			// Crea el intent que comen�ara la partida
			newGame = new Intent(this, GameActivity.class);
			// Afegeix les variables per pasarles a la proxima activity
			newGame.putExtras(extras);
			newGame.putExtra(selectedPlayer, player);
		}
		startActivity(newGame);
		finish();
	}

	private void iaSelectDeck() {
		// Deck de la maquina
		DBAdapter dbAdapter = new DBAdapter(this);
		// Obre la BD
		dbAdapter.open();

		// Variables per capturar les skills del obolo
		String north, south, east, west;

		// numero de Obolos de la llibreria de la maquina
		int maxObolos = 60;
		int count = 0;
		Obolo[] libraryIA = new Obolo[maxObolos];

		// Cursor per capturar les obolos de la base de dades
		Cursor cursor = dbAdapter.getAllObolo();

		if (cursor.moveToFirst()) {
			for (int i = 0; i < (cursor.getCount() - maxObolos); i++)
				cursor.moveToNext();
			do {
				north = String.valueOf(cursor.getString(1));
				south = String.valueOf(cursor.getString(2));
				east = String.valueOf(cursor.getString(3));
				west = String.valueOf(cursor.getString(4));

				// Crea el Obolo capturat desde la base de dades
				Obolo obolo = new Obolo(
						new String[] { north, south, east, west });
				// Inserta el obolo en la llibreria de la IA
				libraryIA[count] = obolo;

				count++;
			} while (cursor.moveToNext() && count < maxObolos);

		}

		dbAdapter.close();

		// Accedeix a les preferencias del joc
		prefs = PreferenceManager.getDefaultSharedPreferences(this);
		String[] strRules = prefs.getString("rules", "").split(
				PackageRulesManager.SEPARATOR);

		// La maquina tria el seu deck segons la seva llibreria i la primera
		// norma, a la alta o a la baixa
		((CPU) player).cpuSelectDeckArray(libraryIA, strRules[0], sizeDeck);

		throwIntentToNewGame();
	}

	private int getPlayerDeckLength(int numRows, int numColumns) {
		// Calcula la mida dels decks dels jugadors
		int size = numRows * numColumns;
		if (size % 2 == 1)
			size++;
		return size / 2;
	}

	private Obolo[] getDeck() {
		// Retorna el deck seleccionat alhora que comen�a el joc

		TableRow trSelectedObolos = (TableRow) tlSelectedObolos.getChildAt(0);
		int position = 0;
		Obolo[] deckUser = new Obolo[sizeDeck];
		do {
			OboloGraphicsView ogvObolo = (OboloGraphicsView) trSelectedObolos
					.getChildAt(position);
			deckUser[position] = ogvObolo.getObolo();
			position++;
		} while (position < trSelectedObolos.getChildCount());
		return deckUser;
	}

	// Touch per als obolos de la matriu gran, es a dir per als obolos que el
	// jugador posseix, no per
	// als obolos que selecciona
	private void setTouchOgvObolo(OboloGraphicsView ogvObolo) {
		ogvObolo.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (!isFull()) {
					final OboloGraphicsView ogvOboloT = (OboloGraphicsView) v;
					if (!ogvOboloT.isPressed()) {
						ogvOboloT.setPressed(true);
						ogvOboloT.setVisibility(INVISIBLE);
						TableRow trSelectedObolos = (TableRow) tlSelectedObolos
								.getChildAt(0);
						int column = nextEmptyColumn();

						OboloGraphicsView ogvOboloDeck = (OboloGraphicsView) trSelectedObolos
								.getChildAt(column);
						ogvOboloDeck.setObolo(ogvOboloT.getObolo());
						cmdNext.setEnabled(canContinue());
						ogvOboloDeck.invalidate();
						// Touch per als obolos de la baralla, es a dir els
						// seleccionats
						ogvOboloDeck.setOnTouchListener(new OnTouchListener() {
							@Override
							public boolean onTouch(View v, MotionEvent event) {
								OboloGraphicsView ogvOboloDeckT = (OboloGraphicsView) v;
								ogvOboloDeckT.setObolo(null);
								ogvOboloT.setPressed(false);
								ogvOboloT.setVisibility(VISIBLE);
								ogvOboloDeckT.invalidate();
								cmdNext.setEnabled(canContinue());
								return false;
							}
						});
					}
				}

				return false;
			}
		});
	}

	private int nextEmptyColumn() {
		boolean emptyColumn = false;
		TableRow trSelectedObolos = (TableRow) tlSelectedObolos.getChildAt(0);
		int column = 0;
		do {
			OboloGraphicsView ogvObolo = (OboloGraphicsView) trSelectedObolos
					.getChildAt(column);
			if (ogvObolo.getObolo() == null) {
				emptyColumn = true;
			} else {
				column++;
			}
		} while (!emptyColumn && column < trSelectedObolos.getChildCount());
		return column;
	}

	private boolean isFull() {
		boolean answer = true;
		TableRow trSelectedObolos = (TableRow) tlSelectedObolos.getChildAt(0);
		int column = 0;
		do {
			OboloGraphicsView ogvObolo = (OboloGraphicsView) trSelectedObolos
					.getChildAt(column);
			if (ogvObolo.getObolo() == null) {
				answer = false;
			} else {
				column++;
			}
		} while (column < trSelectedObolos.getChildCount() && answer);

		return answer;
	}

	private boolean canContinue() {
		TableRow trSelectedObolos = (TableRow) tlSelectedObolos.getChildAt(0);
		boolean answer = false;
		int position = 0;
		int countObolo = 0;
		do {
			OboloGraphicsView ogvOboloDeck = (OboloGraphicsView) trSelectedObolos
					.getChildAt(position);
			if (ogvOboloDeck.getObolo() != null) {
				countObolo++;
			}
			position++;
		} while (position < trSelectedObolos.getChildCount());

		if (countObolo == sizeDeck) {
			answer = true;
		}

		return answer;
	}

	private void boundsViewsOnScreen(double numObolos) {
		// Calcula el heightRatio per donar format a tots els views adequats a
		// la pantalla
		DisplayMetrics metrics = new DisplayMetrics();
		// Recupera el sistema metrico de la pantalla
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		widthRatio = (int) (metrics.widthPixels / numObolos);
	}

}
